home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / unix / tar / part03 < prev    next >
Encoding:
Internet Message Format  |  1990-03-29  |  46.0 KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i128: tar - tape archive utility, Part03/05
  5. Message-ID: <11981@xanth.cs.odu.edu>
  6. Date: 29 Mar 90 03:10:34 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: hue@netcom.uucp (Jonathan Hue)
  9. Lines: 1838
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12. X-Post-Discussions-To: comp.sys.amiga
  13.  
  14. Submitted-by: hue@netcom.uucp (Jonathan Hue)
  15. Posting-number: Volume 90, Issue 128
  16. Archive-name: unix/tar/part03
  17.  
  18. #!/bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 3 (of 5)."
  25. # Contents:  create.c extract.c port.c
  26. # Wrapped by tadguy@xanth on Wed Mar 28 22:07:16 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'create.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'create.c'\"
  30. else
  31. echo shar: Extracting \"'create.c'\" \(15979 characters\)
  32. sed "s/^X//" >'create.c' <<'END_OF_FILE'
  33. X/*
  34. X * Create a tar archive.
  35. X *
  36. X * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  37. X *
  38. X * @(#)create.c 1.36 11/6/87 Public Domain - gnu
  39. X */
  40. X#include <sys/types.h>
  41. X#include <sys/stat.h>
  42. X#include <stdio.h>
  43. X
  44. X#ifndef V7
  45. X#include <fcntl.h>
  46. X#endif
  47. X
  48. X#if !defined(MSDOS) && !defined(AMIGA)
  49. X#include <pwd.h>
  50. X#include <grp.h>
  51. X#endif
  52. X
  53. X#ifdef BSD42
  54. X#include <sys/dir.h>
  55. X#else
  56. X#ifdef MSDOS
  57. X#include <sys/dir.h>
  58. X#else
  59. X#ifdef AMIGA
  60. X#include <dirent.h>
  61. X#else
  62. X/*
  63. X * FIXME: On other systems there is no standard place for the header file
  64. X * for the portable directory access routines.  Change the #include line
  65. X * below to bring it in from wherever it is.
  66. X */
  67. X#include "ndir.h"
  68. X#endif
  69. X#endif
  70. X#endif
  71. X
  72. X#ifdef USG
  73. X#include <sys/sysmacros.h>    /* major() and minor() defined here */
  74. X#endif
  75. X
  76. X/*
  77. X * V7 doesn't have a #define for this.
  78. X */
  79. X#ifndef O_RDONLY
  80. X#define    O_RDONLY    0
  81. X#endif
  82. X
  83. X/*
  84. X * Most people don't have a #define for this.
  85. X */
  86. X#ifndef    O_BINARY
  87. X#define    O_BINARY    0
  88. X#endif
  89. X
  90. X#include "tar.h"
  91. X#include "port.h"
  92. X
  93. Xextern union record *head;        /* Points to current tape header */
  94. Xextern struct stat hstat;        /* Stat struct corresponding */
  95. Xextern int head_standard;        /* Tape header is in ANSI format */
  96. X
  97. X/*
  98. X * If there are no symbolic links, there is no lstat().  Use stat().
  99. X */
  100. X#ifndef S_IFLNK
  101. X#define lstat stat
  102. X#endif
  103. X
  104. Xextern char    *malloc();
  105. Xextern char    *strcpy();
  106. Xextern char    *strncpy();
  107. Xextern void    bzero();
  108. Xextern void    bcopy();
  109. Xextern int    errno;
  110. X
  111. Xextern void print_header();
  112. X
  113. Xunion record *start_header();
  114. Xvoid finish_header();
  115. Xvoid finduname();
  116. Xvoid findgname();
  117. Xchar *name_next();
  118. Xvoid to_oct(), to_hex();
  119. Xvoid dump_file();
  120. X
  121. Xstatic nolinks;            /* Gets set if we run out of RAM */
  122. X
  123. Xvoid
  124. Xcreate_archive()
  125. X{
  126. X    register char    *p;
  127. X
  128. X    open_archive(0);        /* Open for writing */
  129. X
  130. X    while (p = name_next()) {
  131. X#ifdef AMIGA
  132. X        if (!strcmp(p, "."))    /* convert . and ./ to "" */
  133. X            p++;
  134. X        else if (!strcmp(p, "./"))
  135. X            p += 2;
  136. X#endif
  137. X        dump_file(p, -1);
  138. X    }
  139. X
  140. X    write_eot();
  141. X    close_archive();
  142. X    name_close();
  143. X}        
  144. X
  145. X/*
  146. X * Dump a single file.  If it's a directory, recurse.
  147. X * Result is 1 for success, 0 for failure.
  148. X * Sets global "hstat" to stat() output for this file.
  149. X */
  150. Xvoid
  151. Xdump_file(p, curdev)
  152. X    char    *p;            /* File name to dump */
  153. X    int    curdev;            /* Device our parent dir was on */
  154. X{
  155. X    union record    *header;
  156. X    char type;
  157. X
  158. X    /*
  159. X     * Use stat if following (rather than dumping) 4.2BSD's
  160. X     * symbolic links.  Otherwise, use lstat (which, on non-4.2
  161. X     * systems, is #define'd to stat anyway.
  162. X     */
  163. X    if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat))
  164. X    {
  165. Xbadperror:
  166. X        perror(p);
  167. Xbadfile:
  168. X        errors++;
  169. X        return;
  170. X    }
  171. X
  172. X    /*
  173. X     * See if we are crossing from one file system to another,
  174. X     * and avoid doing so if the user only wants to dump one file system.
  175. X     */
  176. X    if (f_local_filesys && curdev >= 0 && curdev != hstat.st_dev) {
  177. X        annorec(stderr, tar);
  178. X        fprintf(stderr,
  179. X            "%s: is on a different filesystem; not dumped\n",
  180. X            p);
  181. X        return;
  182. X    }
  183. X#ifdef AMIGA
  184. X    /*
  185. X     * If f_archive_check is set, check the archived bit of the
  186. X     * file and don't archive it if the bit is set and it's a normal
  187. X       * file.
  188. X     */
  189. X    if (f_archive_check && (hstat.st_prot & FIBF_ARCHIVE) &&
  190. X        !(hstat.st_mode & S_IFDIR))
  191. X    {
  192. X        if (f_verbose > 1)
  193. X        {
  194. X        annorec(stderr, tar);
  195. X        fprintf(stderr, "%s: archive bit set, not dumping\n", p);
  196. X        }
  197. X        return;
  198. X    }    
  199. X#endif
  200. X
  201. X    /*
  202. X     * Check for multiple links.
  203. X     *
  204. X     * We maintain a list of all such files that we've written so
  205. X     * far.  Any time we see another, we check the list and
  206. X     * avoid dumping the data again if we've done it once already.
  207. X     */
  208. X    if (hstat.st_nlink > 1) switch (hstat.st_mode & S_IFMT) {
  209. X        register struct link    *lp;
  210. X
  211. X    case S_IFREG:            /* Regular file */
  212. X#ifdef S_IFCTG
  213. X    case S_IFCTG:            /* Contigous file */
  214. X#endif
  215. X#ifdef S_IFCHR
  216. X    case S_IFCHR:            /* Character special file */
  217. X#endif
  218. X
  219. X#ifdef S_IFBLK
  220. X    case S_IFBLK:            /* Block     special file */
  221. X#endif
  222. X
  223. X#ifdef S_IFIFO
  224. X    case S_IFIFO:            /* Fifo      special file */
  225. X#endif
  226. X
  227. X        /* First quick and dirty.  Hashing, etc later FIXME */
  228. X        for (lp = linklist; lp; lp = lp->next) {
  229. X            if (lp->ino == hstat.st_ino &&
  230. X                lp->dev == hstat.st_dev) {
  231. X                /* We found a link. */
  232. X                hstat.st_size = 0;
  233. X                header = start_header(p, &hstat);
  234. X                if (header == NULL) goto badfile;
  235. X                strcpy(header->header.linkname,
  236. X                    lp->name);
  237. X                header->header.linkflag = LF_LINK;
  238. X                finish_header(header);
  239. X        /* FIXME: Maybe remove from list after all links found? */
  240. X                return;        /* We dumped it */
  241. X            }
  242. X        }
  243. X
  244. X        /* Not found.  Add it to the list of possible links. */
  245. X        lp = (struct link *) malloc( (unsigned)
  246. X            (strlen(p) + sizeof(struct link) - NAMSIZ));
  247. X        if (!lp) {
  248. X            if (!nolinks) {
  249. X                fprintf(stderr,
  250. X    "tar: no memory for links, they will be dumped as separate files\n");
  251. X                nolinks++;
  252. X            }
  253. X        }
  254. X        lp->ino = hstat.st_ino;
  255. X        lp->dev = hstat.st_dev;
  256. X        strcpy(lp->name, p);
  257. X        lp->next = linklist;
  258. X        linklist = lp;
  259. X    }
  260. X
  261. X    /*
  262. X     * This is not a link to a previously dumped file, so dump it.
  263. X     */
  264. X    switch (hstat.st_mode & S_IFMT) {
  265. X
  266. X    case S_IFREG:            /* Regular file */
  267. X#ifdef S_IFCTG
  268. X    case S_IFCTG:            /* Contigous file */
  269. X#endif
  270. X    {
  271. X        int    f;        /* File descriptor */
  272. X        int    bufsize, count;
  273. X        register long    sizeleft;
  274. X        register union record     *start;
  275. X
  276. X        sizeleft = hstat.st_size;
  277. X        /* Don't bother opening empty, world readable files. */
  278. X        if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode)) {
  279. X            f = open(p, O_RDONLY|O_BINARY);
  280. X            if (f < 0) goto badperror;
  281. X        } else {
  282. X            f = -1;
  283. X        }
  284. X        header = start_header(p, &hstat);
  285. X        if (header == NULL) goto badfile;
  286. X#ifdef S_IFCTG
  287. X        /* Mark contiguous files, if we support them */
  288. X        if (f_standard && (hstat.st_mode & S_IFMT) == S_IFCTG) {
  289. X            header->header.linkflag = LF_CONTIG;
  290. X        }
  291. X#endif
  292. X        finish_header(header);
  293. X        while (sizeleft > 0) {
  294. X            start = findrec();
  295. X            bufsize = endofrecs()->charptr - start->charptr;
  296. X            if (sizeleft < bufsize) {
  297. X                /* Last read -- zero out area beyond */
  298. X                bufsize = (int)sizeleft;
  299. X                count = bufsize % RECORDSIZE;
  300. X                if (count) 
  301. X                    bzero(start->charptr + sizeleft,
  302. X                        RECORDSIZE - count);
  303. X            }
  304. X            count = read(f, start->charptr, bufsize);
  305. X            if (count < 0) {
  306. X                annorec(stderr, tar);
  307. X                fprintf(stderr,
  308. X                  "read error at byte %ld, reading %d bytes, in file ",
  309. X                    hstat.st_size - sizeleft,
  310. X                    bufsize);
  311. X                perror(p);    /* FIXME */
  312. X                goto padit;
  313. X            }
  314. X            sizeleft -= count;
  315. X            /* This is nonportable (the type of userec's arg). */
  316. X            userec(start+(count-1)/RECORDSIZE);
  317. X            if (count == bufsize) continue;
  318. X            annorec(stderr, tar);
  319. X            fprintf(stderr,
  320. X              "%s: file shrunk by %d bytes, padding with zeros.\n",
  321. X                p, sizeleft);
  322. X            goto padit;        /* Short read */
  323. X        }
  324. X        if (f >= 0)
  325. X            (void)close(f);
  326. X#ifdef AMIGA
  327. X        if (f_archive_set)
  328. X        {
  329. X            if (SmartSetProtection(p, hstat.st_prot | 
  330. X            FIBF_ARCHIVE) < 0)
  331. X            {
  332. X                fputs("tar: Error setting archive bit on ", stderr);
  333. X            perror(p);
  334. X            }
  335. X        }
  336. X#endif        
  337. X        break;
  338. X
  339. X        /*
  340. X         * File shrunk or gave error, pad out tape to match
  341. X         * the size we specified in the header.
  342. X         */
  343. X    padit:
  344. X        abort();
  345. X    }
  346. X
  347. X#ifdef S_IFLNK
  348. X    case S_IFLNK:            /* Symbolic link */
  349. X    {
  350. X        int size;
  351. X
  352. X        hstat.st_size = 0;        /* Force 0 size on symlink */
  353. X        header = start_header(p, &hstat);
  354. X        if (header == NULL) goto badfile;
  355. X        size = readlink(p, header->header.linkname, NAMSIZ);
  356. X        if (size < 0) goto badperror;
  357. X        if (size == NAMSIZ) {
  358. X            annorec(stderr, tar);
  359. X            fprintf(stderr,
  360. X                "%s: symbolic link too long\n", p);
  361. X            break;
  362. X        }
  363. X        header->header.linkname[size] = '\0';
  364. X        header->header.linkflag = LF_SYMLINK;
  365. X        finish_header(header);        /* Nothing more to do to it */
  366. X    }
  367. X        break;
  368. X#endif
  369. X
  370. X    case S_IFDIR:            /* Directory */
  371. X    {
  372. X        register DIR *dirp;
  373. X        register struct dirent *d;
  374. X        char namebuf[NAMSIZ+2];
  375. X        register int len;
  376. X        int our_device = hstat.st_dev;
  377. X
  378. X        /* Build new prototype name */
  379. X        strncpy(namebuf, p, sizeof (namebuf));
  380. X#ifdef AMIGA
  381. X        /*
  382. X         * If user types "" (current dir), make namebuf be ./ - this
  383. X         * will later be stripped.
  384. X         */
  385. X        if (!*namebuf) {
  386. X            strcpy(namebuf, "./");
  387. X        }
  388. X#endif
  389. X        len = strlen(namebuf);
  390. X        while (len >= 1 && '/' == namebuf[len-1]) 
  391. X            len--;            /* Delete trailing slashes */
  392. X#ifdef AMIGA
  393. X        if (namebuf[len - 1] != ':')     /* no / after : */
  394. X            namebuf[len++] = '/';    /* Now add exactly one back */
  395. X#else
  396. X        namebuf[len++] = '/';        /* Now add exactly one back */
  397. X#endif
  398. X        namebuf[len] = '\0';        /* Make sure null-terminated */
  399. X        /*
  400. X         * Output directory header record with permissions
  401. X         * FIXME, do this AFTER files, to avoid R/O dir problems?
  402. X         * If old archive format, don't write record at all.
  403. X         */
  404. X        if (!f_oldarch) {
  405. X            hstat.st_size = 0;    /* Force 0 size on dir */
  406. X            /*
  407. X             * If people could really read standard archives,
  408. X             * this should be:        (FIXME)
  409. X            header = start_header(f_standard? p: namebuf, &hstat);
  410. X             * but since they'd interpret LF_DIR records as
  411. X             * regular files, we'd better put the / on the name.
  412. X             */
  413. X            header = start_header(namebuf, &hstat);
  414. X            if (header == NULL)
  415. X                goto badfile;    /* eg name too long */
  416. X            if (f_standard) {
  417. X                header->header.linkflag = LF_DIR;
  418. X            }
  419. X            finish_header(header);    /* Done with directory header */
  420. X        }
  421. X
  422. X        /* Hack to remove "./" from the front of all the file names */
  423. X        if (len == 2 && namebuf[0] == '.') {
  424. X            len = 0;
  425. X        }
  426. X
  427. X        /* Now output all the files in the directory */
  428. X        if (f_dironly)
  429. X            break;        /* Unless the user says no */
  430. X        errno = 0;
  431. X        dirp = opendir(p);
  432. X        if (!dirp) {
  433. X            if (errno) {
  434. X                perror (p);
  435. X            } else {
  436. X                annorec(stderr, tar);
  437. X                fprintf(stderr, "%s: error opening directory",
  438. X                    p);
  439. X            }
  440. X            break;
  441. X        }
  442. X        
  443. X        /* Should speed this up by cd-ing into the dir, FIXME */
  444. X        while (NULL != (d=readdir(dirp))) {
  445. X            /* Skip . and .. */
  446. X            if (d->d_name[0] == '.') {
  447. X                if (d->d_name[1] == '\0') continue;
  448. X                if (d->d_name[1] == '.') {
  449. X                    if (d->d_name[2] == '\0') continue;
  450. X                }
  451. X            }
  452. X            if (strlen(d->d_name) + len >= NAMSIZ) {
  453. X                annorec(stderr, tar);
  454. X                fprintf(stderr, "%s%s: name too long\n", 
  455. X                    namebuf, d->d_name);
  456. X                continue;
  457. X            }
  458. X            strcpy(namebuf+len, d->d_name);
  459. X            dump_file(namebuf, our_device);
  460. X        }
  461. X
  462. X        closedir(dirp);
  463. X#ifdef AMIGA
  464. X        if (f_archive_set)
  465. X        {
  466. X            if (SmartSetProtection(p, hstat.st_prot | 
  467. X            FIBF_ARCHIVE) < 0)
  468. X            {
  469. X                fputs("tar: Error setting archive bit on ", stderr);
  470. X            perror(p);
  471. X            }
  472. X        }
  473. X#endif
  474. X    }
  475. X        break;
  476. X
  477. X#ifdef S_IFCHR
  478. X    case S_IFCHR:            /* Character special file */
  479. X        type = LF_CHR;
  480. X        goto easy;
  481. X#endif
  482. X
  483. X#ifdef S_IFBLK
  484. X    case S_IFBLK:            /* Block     special file */
  485. X        type = LF_BLK;
  486. X        goto easy;
  487. X#endif
  488. X
  489. X#ifdef S_IFIFO
  490. X    case S_IFIFO:            /* Fifo      special file */
  491. X        type = LF_FIFO;
  492. X#endif
  493. X
  494. X    easy:
  495. X        if (!f_standard) goto unknown;
  496. X
  497. X        hstat.st_size = 0;        /* Force 0 size */
  498. X        header = start_header(p, &hstat);
  499. X        if (header == NULL) goto badfile;    /* eg name too long */
  500. X
  501. X        header->header.linkflag = type;
  502. X        if (type != LF_FIFO) {
  503. X            to_oct((long) major(hstat.st_rdev), 8,
  504. X                header->header.devmajor);
  505. X            to_oct((long) minor(hstat.st_rdev), 8,
  506. X                header->header.devminor);
  507. X        }
  508. X
  509. X        finish_header(header);
  510. X        break;
  511. X
  512. X    default:
  513. X    unknown:
  514. X        annorec(stderr, tar);
  515. X        fprintf(stderr,
  516. X            "%s: Unknown file type; file ignored.\n", p);
  517. X        break;
  518. X    }
  519. X}
  520. X
  521. X
  522. X/*
  523. X * Make a header block for the file  name  whose stat info is  st .
  524. X * Return header pointer for success, NULL if the name is too long.
  525. X */
  526. Xunion record *
  527. Xstart_header(name, st)
  528. X    char    *name;
  529. X    register struct stat *st;
  530. X{
  531. X    register union record *header;
  532. X    char newname[NAMSIZ+2];
  533. X    header = (union record *) findrec();
  534. X    bzero(header->charptr, sizeof(*header)); /* XXX speed up */
  535. X
  536. X    /*
  537. X     * Check the file name and put it in the record.
  538. X     */
  539. X#ifdef AMIGA
  540. X    cvtAmi2UNIX(name, newname);
  541. X    name = newname;    /* point name at newname, but leave orig string alone */
  542. X#else
  543. X    while ('/' == *name) {
  544. X        static int warned_once = 0;
  545. X
  546. X        name++;                /* Force relative path */
  547. X        if (!warned_once++) {
  548. X            annorec(stderr, tar);
  549. X            fprintf(stderr,
  550. X    "Removing leading / from absolute path names in the archive.\n");
  551. X        }
  552. X    }
  553. X#endif
  554. X    strcpy(header->header.name, name);
  555. X    if (header->header.name[NAMSIZ-1]) {
  556. X        annorec(stderr, tar);
  557. X        fprintf(stderr, "%s: name too long\n", name);
  558. X        return NULL;
  559. X    }
  560. X
  561. X    to_oct((long) (st->st_mode & ~S_IFMT),
  562. X                    8,  header->header.mode);
  563. X    to_oct((long) st->st_uid,    8,  header->header.uid);
  564. X    to_oct((long) st->st_gid,    8,  header->header.gid);
  565. X    to_oct((long) st->st_size,    1+12, header->header.size);
  566. X    to_oct((long) st->st_mtime,    1+12, header->header.mtime);
  567. X    /* header->header.linkflag is left as null */
  568. X#ifdef AMIGA
  569. X    strcpy(header->header.magic_cookie, "AmigaTar");
  570. X    to_hex(st->st_prot, header->header.amiga_modes);
  571. X    memset(header->header.comment, '\0', sizeof(header->header.comment));
  572. X    strcpy(header->header.comment, st->st_comment);
  573. X    to_hex(st->st_date.ds_Days, header->header.ds_Days);
  574. X    to_hex(st->st_date.ds_Minute, header->header.ds_Minute);
  575. X    to_hex(st->st_date.ds_Tick, header->header.ds_Tick);
  576. X#endif
  577. X#ifndef NONAMES
  578. X    /* Fill in new Unix Standard fields if desired. */
  579. X    if (f_standard) {
  580. X        header->header.linkflag = LF_NORMAL;    /* New default */
  581. X        strcpy(header->header.magic, TMAGIC);    /* Mark as Unix Std */
  582. X        finduname(header->header.uname, st->st_uid);
  583. X        findgname(header->header.gname, st->st_gid);
  584. X    }
  585. X#endif
  586. X    return header;
  587. X}
  588. X
  589. X/* 
  590. X * Finish off a filled-in header block and write it out.
  591. X * We also print the file name and/or full info if verbose is on.
  592. X */
  593. Xvoid
  594. Xfinish_header(header)
  595. X    register union record *header;
  596. X{
  597. X    register int    i, sum;
  598. X    register char    *p;
  599. X
  600. X    bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum));
  601. X
  602. X    sum = 0;
  603. X    p = header->charptr;
  604. X    for (i = sizeof(*header); --i >= 0; ) {
  605. X        /*
  606. X         * We can't use unsigned char here because of old compilers,
  607. X         * e.g. V7.
  608. X         */
  609. X        sum += 0xFF & *p++;
  610. X    }
  611. X
  612. X    /*
  613. X     * Fill in the checksum field.  It's formatted differently
  614. X     * from the other fields:  it has [6] digits, a null, then a
  615. X     * space -- rather than digits, a space, then a null.
  616. X     * We use to_oct then write the null in over to_oct's space.
  617. X     * The final space is already there, from checksumming, and
  618. X     * to_oct doesn't modify it.
  619. X     *
  620. X     * This is a fast way to do:
  621. X     * (void) sprintf(header->header.chksum, "%6o", sum);
  622. X     */
  623. X    to_oct((long) sum,    8,  header->header.chksum);
  624. X    header->header.chksum[6] = '\0';    /* Zap the space */
  625. X
  626. X    userec(header);
  627. X
  628. X    if (f_verbose) {
  629. X        /* These globals are parameters to print_header, sigh */
  630. X        head = header;
  631. X        /* hstat is already set up */
  632. X        head_standard = f_standard;
  633. X        print_header(stderr);
  634. X    }
  635. X
  636. X    return;
  637. X}
  638. X
  639. X
  640. X/*
  641. X * Quick and dirty octal conversion.
  642. X * Converts long "value" into a "digs"-digit field at "where",
  643. X * including a trailing space and room for a null.  "digs"==3 means
  644. X * 1 digit, a space, and room for a null.
  645. X *
  646. X * We assume the trailing null is already there and don't fill it in.
  647. X * This fact is used by start_header and finish_header, so don't change it!
  648. X *
  649. X * This should be equivalent to:
  650. X *    (void) sprintf(where, "%*lo ", digs-2, value);
  651. X * except that sprintf fills in the trailing null and we don't.
  652. X */
  653. Xvoid
  654. Xto_oct(value, digs, where)
  655. X    register long    value;
  656. X    register int    digs;
  657. X    register char    *where;
  658. X{
  659. X    
  660. X    --digs;                /* Trailing null slot is left alone */
  661. X    where[--digs] = ' ';        /* Put in the space, though */
  662. X
  663. X    /* Produce the digits -- at least one */
  664. X    do {
  665. X        where[--digs] = '0' + (char)(value & 7); /* one octal digit */
  666. X        value >>= 3;
  667. X    } while (digs > 0 && value != 0);
  668. X
  669. X    /* Leading spaces, if necessary */
  670. X    while (digs > 0)
  671. X        where[--digs] = ' ';
  672. X
  673. X}
  674. X
  675. X
  676. X/*
  677. X * Write the EOT record(s).
  678. X * We actually zero at least one record, through the end of the block.
  679. X * Old tar writes garbage after two zeroed records -- and PDtar used to.
  680. X */
  681. Xwrite_eot()
  682. X{
  683. X    union record *p;
  684. X    int bufsize;
  685. X
  686. X    p = findrec();
  687. X    bufsize = endofrecs()->charptr - p->charptr;
  688. X    bzero(p->charptr, bufsize);
  689. X    userec(p);
  690. X}
  691. X
  692. X#ifdef AMIGA
  693. X/*
  694. X * 32-bit to 8 ascii chars as hex plus null term
  695. X */
  696. Xvoid
  697. Xto_hex(u_long val, char *p)
  698. X{
  699. X    int i, nibble;
  700. X
  701. X    p += 8;            /* point to last char */
  702. X    *p = '\0';            /* null term */
  703. X    for (i = 0; i < 8; i++)
  704. X    {
  705. X    nibble = val & 0xf;
  706. X    *--p = (nibble > 9) ? (nibble - 10) + 'a' : nibble + '0';
  707. X    val >>= 4;
  708. X    }
  709. X}
  710. X#endif
  711. END_OF_FILE
  712. if test 15979 -ne `wc -c <'create.c'`; then
  713.     echo shar: \"'create.c'\" unpacked with wrong size!
  714. fi
  715. # end of 'create.c'
  716. fi
  717. if test -f 'extract.c' -a "${1}" != "-c" ; then 
  718.   echo shar: Will not clobber existing file \"'extract.c'\"
  719. else
  720. echo shar: Extracting \"'extract.c'\" \(13710 characters\)
  721. sed "s/^X//" >'extract.c' <<'END_OF_FILE'
  722. X/*
  723. X * Extract files from a tar archive.
  724. X *
  725. X * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  726. X *
  727. X * @(#) extract.c 1.32 87/11/11 Public Domain - gnu
  728. X */
  729. X
  730. X#include <stdio.h>
  731. X#include <errno.h>
  732. X#include <sys/types.h>
  733. X#include <sys/stat.h>
  734. X
  735. X#ifdef BSD42
  736. X#include <sys/file.h>
  737. X#endif
  738. X
  739. X#ifdef USG
  740. X#include <fcntl.h>
  741. X#endif
  742. X
  743. X#if defined(MSDOS) || defined(AMIGA)
  744. X#include <fcntl.h>
  745. X#endif    /* MSDOS */
  746. X
  747. X/*
  748. X * Some people don't have a #define for these.
  749. X */
  750. X#ifndef    O_BINARY
  751. X#define    O_BINARY    0
  752. X#endif
  753. X#ifndef O_NDELAY
  754. X#define    O_NDELAY    0
  755. X#endif
  756. X
  757. X#ifdef NO_OPEN3
  758. X/* We need the #define's even though we don't use them. */
  759. X#include "open3.h"
  760. X#endif
  761. X
  762. X#ifdef EMUL_OPEN3
  763. X/* Simulated 3-argument open for systems that don't have it */
  764. X#include "open3.h"
  765. X#endif
  766. X
  767. Xextern int errno;            /* From libc.a */
  768. Xextern time_t time();            /* From libc.a */
  769. Xextern char *index();            /* From libc.a or port.c */
  770. X
  771. X#include "tar.h"
  772. X#include "port.h"
  773. X
  774. Xextern union record *head;        /* Points to current tape header */
  775. Xextern struct stat hstat;        /* Stat struct corresponding */
  776. Xextern int head_standard;        /* Tape header is in ANSI format */
  777. X
  778. Xextern void print_header();
  779. Xextern void skip_file();
  780. Xextern void pr_mkdir();
  781. X
  782. Xint make_dirs();            /* Makes required directories */
  783. X#ifdef AMIGA
  784. Xextern int made_on_amiga;        /* decode_header() sets this if tar
  785. X                     * was made on Amiga.  Passing this
  786. X                     * as a param would change too much
  787. X                     * code so we make it a global */
  788. X#endif
  789. X
  790. Xstatic time_t now = 0;            /* Current time */
  791. Xstatic we_are_root = 0;            /* True if our effective uid == 0 */
  792. Xstatic int notumask = ~0;        /* Masks out bits user doesn't want */
  793. X
  794. X/*
  795. X * Set up to extract files.
  796. X */
  797. Xextr_init()
  798. X{
  799. X    int ourmask;
  800. X
  801. X    now = time((time_t *)0);
  802. X    if (geteuid() == 0)
  803. X        we_are_root = 1;
  804. X
  805. X    /*
  806. X     * We need to know our umask.  But if f_use_protection is set,
  807. X     * leave our kernel umask at 0, and our "notumask" at ~0.
  808. X     */
  809. X    ourmask = umask(0);        /* Read it */
  810. X    if (!f_use_protection) {
  811. X        (void) umask (ourmask);    /* Set it back how it was */
  812. X        notumask = ~ourmask;    /* Make umask override permissions */
  813. X    }
  814. X}
  815. X
  816. X
  817. X/*
  818. X * Extract a file from the archive.
  819. X */
  820. Xvoid
  821. Xextract_archive()
  822. X{
  823. X    register char *data;
  824. X    int fd, check, namelen, written, openflag;
  825. X    long size;
  826. X    time_t acc_upd_times[2];
  827. X    register int skipcrud;
  828. X#ifdef AMIGA
  829. X    int protection;        /* protection bits */
  830. X#endif
  831. X
  832. X    saverec(&head);            /* Make sure it sticks around */
  833. X    userec(head);            /* And go past it in the archive */
  834. X    decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  835. X
  836. X    /* Print the record from 'head' and 'hstat' */
  837. X    if (f_verbose)
  838. X        print_header(stdout);
  839. X
  840. X    /*
  841. X     * Check for fully specified pathnames and other atrocities.
  842. X     *
  843. X     * Note, we can't just make a pointer to the new file name,
  844. X     * since saverec() might move the header and adjust "head".
  845. X     * We have to start from "head" every time we want to touch
  846. X     * the header record.
  847. X     */
  848. X    skipcrud = 0;
  849. X    while ('/' == head->header.name[skipcrud]) {
  850. X        static int warned_once = 0;
  851. X
  852. X        skipcrud++;    /* Force relative path */
  853. X        if (!warned_once++) {
  854. X            annorec(stderr, tar);
  855. X            fprintf(stderr,
  856. X    "Removing leading / from absolute path names in the archive.\n");
  857. X        }
  858. X    }
  859. X#ifdef AMIGA
  860. X    cvtUNIX2Ami(skipcrud + head->header.name);
  861. X#endif
  862. X    switch (head->header.linkflag) {
  863. X
  864. X    default:
  865. X        annofile(stderr, tar);
  866. X        fprintf(stderr,
  867. X           "Unknown file type '%c' for %s, extracted as normal file\n",
  868. X            head->header.linkflag, skipcrud+head->header.name);
  869. X        /* FALL THRU */
  870. X
  871. X    case LF_OLDNORMAL:
  872. X    case LF_NORMAL:
  873. X    case LF_CONTIG:
  874. X        /*
  875. X         * Appears to be a file.
  876. X         * See if it's really a directory.
  877. X         */
  878. X        namelen = strlen(skipcrud+head->header.name)-1;
  879. X        if (head->header.name[skipcrud+namelen] == '/')
  880. X            goto really_dir;
  881. X
  882. X        /* FIXME, deal with protection issues */
  883. X    again_file:
  884. X#if defined(AMIGA) && defined(LATTICE)    /* open w/O_EXCL is broken, sigh */
  885. X        openflag = O_BINARY|O_NDELAY|O_WRONLY|O_APPEND|O_CREAT|O_TRUNC;
  886. X#else
  887. X        openflag = f_keep?
  888. X            O_BINARY|O_NDELAY|O_WRONLY|O_APPEND|O_CREAT|O_EXCL:
  889. X            O_BINARY|O_NDELAY|O_WRONLY|O_APPEND|O_CREAT|O_TRUNC;
  890. X#endif
  891. X
  892. X#ifdef O_CTG
  893. X        /*
  894. X         * Contiguous files (on the Masscomp) have to specify
  895. X         * the size in the open call that creates them.
  896. X         */
  897. X        if (head->header.lnkflag == LF_CONTIG)
  898. X            fd = open(skipcrud+head->header.name, openflag | O_CTG,
  899. X                hstat.st_mode, hstat.st_size);
  900. X        else
  901. X#endif
  902. X        {
  903. X#ifdef NO_OPEN3
  904. X            /*
  905. X             * On raw V7 we won't let them specify -k (f_keep), but
  906. X             * we just bull ahead and create the files.
  907. X             */
  908. X            fd = creat(skipcrud+head->header.name, 
  909. X                hstat.st_mode);
  910. X#else
  911. X            /*
  912. X             * With 3-arg open(), we can do this up right.
  913. X             */
  914. X#if defined(AMIGA) && defined(LATTICE)
  915. X            if (f_keep && !access(skipcrud+head->header.name,
  916. X                         O_RDONLY))
  917. X            {
  918. X                fd = -1;
  919. X                errno = EEXIST;
  920. X            }
  921. X            else
  922. X                fd = open(skipcrud+head->header.name, openflag,
  923. X                      hstat.st_mode);
  924. X#endif
  925. X#endif
  926. X        }
  927. X
  928. X        if (fd < 0) {
  929. X            if (make_dirs(skipcrud+head->header.name))
  930. X                goto again_file;
  931. X            annofile(stderr, tar);
  932. X            fprintf(stderr, "Could not make file ");
  933. X            perror(skipcrud+head->header.name);
  934. X            skip_file((long)hstat.st_size);
  935. X            goto quit;
  936. X        }
  937. X
  938. X        for (size = hstat.st_size;
  939. X             size > 0;
  940. X             size -= written) {
  941. X            /*
  942. X             * Locate data, determine max length
  943. X             * writeable, write it, record that
  944. X             * we have used the data, then check
  945. X             * if the write worked.
  946. X             */
  947. X            data = findrec()->charptr;
  948. X            if (data == NULL) {    /* Check it... */
  949. X                annorec(stderr, tar);
  950. X                fprintf(stderr, "Unexpected EOF on archive file\n");
  951. X                break;
  952. X            }
  953. X            written = endofrecs()->charptr - data;
  954. X            if (written > size) written = size;
  955. X            errno = 0;
  956. X            check = write(fd, data, written);
  957. X            /*
  958. X             * The following is in violation of strict
  959. X             * typing, since the arg to userec
  960. X             * should be a struct rec *.  FIXME.
  961. X             */
  962. X            userec(data + written - 1);
  963. X            if (check == written) continue;
  964. X            /*
  965. X             * Error in writing to file.
  966. X             * Print it, skip to next file in archive.
  967. X             */
  968. X            annofile(stderr, tar);
  969. X            fprintf(stderr,
  970. X    "Tried to write %d bytes to file, could only write %d:\n",
  971. X                written, check);
  972. X            perror(skipcrud+head->header.name);
  973. X            skip_file((long)(size - written));
  974. X            break;    /* Still do the close, mod time, chmod, etc */
  975. X        }
  976. X
  977. X        check = close(fd);
  978. X        if (check < 0) {
  979. X            annofile(stderr, tar);
  980. X            fprintf(stderr, "Error while closing ");
  981. X            perror(skipcrud+head->header.name);
  982. X        }
  983. X        
  984. X    set_filestat:
  985. X#ifdef AMIGA
  986. X        /*
  987. X         * Set the comment on the file
  988. X         */
  989. X        if (made_on_amiga)
  990. X        {
  991. X            if (SmartSetComment(skipcrud+head->header.name,
  992. X                    hstat.st_comment) < 0)
  993. X            {
  994. X            annofile(stderr, tar);
  995. X            fputs("failed to set comment on ", stderr);
  996. X            perror(skipcrud+head->header.name);
  997. X            }
  998. X        }
  999. X#endif
  1000. X        /*
  1001. X         * Set the modified time of the file.
  1002. X         * 
  1003. X         * Note that we set the accessed time to "now", which
  1004. X         * is really "the time we started extracting files".
  1005. X         */
  1006. X        if (!f_modified) {
  1007. X            acc_upd_times[0] = now;             /* Accessed now */
  1008. X            acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
  1009. X#ifdef AMIGA
  1010. X            if (made_on_amiga) {
  1011. X                if (utime_from_stamp(skipcrud+head->header.name,
  1012. X                    &(hstat.st_date)) < 0) {
  1013. X                    annofile(stderr, tar);
  1014. X                    fputs("utime failed:", stderr);
  1015. X                    perror(skipcrud+head->header.name);
  1016. X                }
  1017. X            } else {
  1018. X#endif
  1019. X            if (utime(skipcrud+head->header.name,
  1020. X                acc_upd_times) < 0) {
  1021. X                annofile(stderr, tar);
  1022. X                fputs("utime failed:", stderr);
  1023. X                perror(skipcrud+head->header.name);
  1024. X            }
  1025. X#ifdef AMIGA
  1026. X            }
  1027. X#endif
  1028. X        }
  1029. X
  1030. X        /*
  1031. X         * If we are root, set the owner and group of the extracted
  1032. X         * file.  This does what is wanted both on real Unix and on
  1033. X         * System V.  If we are running as a user, we extract as that
  1034. X         * user; if running as root, we extract as the original owner.
  1035. X         */
  1036. X        if (we_are_root) {
  1037. X            if (chown(skipcrud+head->header.name, hstat.st_uid,
  1038. X                  hstat.st_gid) < 0) {
  1039. X                annofile(stderr, tar);
  1040. X                perror(skipcrud+head->header.name);
  1041. X            }
  1042. X        }
  1043. X
  1044. X        /*
  1045. X         * If '-k' is not set, open() or creat() could have saved
  1046. X         * the permission bits from a previously created file,
  1047. X         * ignoring the ones we specified.
  1048. X         * Even if -k is set, if the file has abnormal
  1049. X         * mode bits, we must chmod since writing or chown() has
  1050. X         * probably reset them.
  1051. X         *
  1052. X         * If -k is set, we know *we* created this file, so the mode
  1053. X         * bits were set by our open().   If the file is "normal", we
  1054. X         * skip the chmod.  This works because we did umask(0) if -p
  1055. X         * is set, so umask will have left the specified mode alone.
  1056. X         */
  1057. X#ifdef AMIGA
  1058. X        /*
  1059. X         * open() ignores modes, so always do this unless
  1060. X         */
  1061. X        if (made_on_amiga)
  1062. X            protection = hstat.st_prot & ~FIBF_ARCHIVE;
  1063. X        else
  1064. X            protection = ~((hstat.st_mode >> 5) | 1) & 0xf;
  1065. X        if (SmartSetProtection(skipcrud+head->header.name,
  1066. X                       protection) < 0)
  1067. X        {
  1068. X            annofile(stderr, tar);
  1069. X            fputs("failed to set protection on ", stderr);
  1070. X            perror(skipcrud+head->header.name);
  1071. X        }
  1072. X#else
  1073. X        if ((!f_keep)
  1074. X            || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
  1075. X            if (chmod(skipcrud+head->header.name,
  1076. X                  notumask & (int)hstat.st_mode) < 0) {
  1077. X                annofile(stderr, tar);
  1078. X                perror(skipcrud+head->header.name);
  1079. X            }
  1080. X        }
  1081. X#endif
  1082. X
  1083. X    quit:
  1084. X        break;
  1085. X
  1086. X    case LF_LINK:
  1087. X    again_link:
  1088. X        check = link (head->header.linkname,
  1089. X                  skipcrud+head->header.name);
  1090. X        if (check == 0)
  1091. X            break;
  1092. X        if (make_dirs(skipcrud+head->header.name))
  1093. X            goto again_link;
  1094. X        annofile(stderr, tar);
  1095. X        fprintf(stderr, "Could not link %s to ",
  1096. X            skipcrud+head->header.name);
  1097. X        perror(head->header.linkname);
  1098. X        break;
  1099. X
  1100. X#ifdef S_IFLNK
  1101. X    case LF_SYMLINK:
  1102. X    again_symlink:
  1103. X        check = symlink(head->header.linkname,
  1104. X                    skipcrud+head->header.name);
  1105. X        /* FIXME, don't worry uid, gid, etc... */
  1106. X        if (check == 0)
  1107. X            break;
  1108. X        if (make_dirs(skipcrud+head->header.name))
  1109. X            goto again_symlink;
  1110. X        annofile(stderr, tar);
  1111. X        fprintf(stderr, "Could not create symlink ");
  1112. X        perror(head->header.linkname);
  1113. X        break;
  1114. X#endif
  1115. X
  1116. X#ifdef S_IFCHR
  1117. X    case LF_CHR:
  1118. X        hstat.st_mode |= S_IFCHR;
  1119. X        goto make_node;
  1120. X#endif
  1121. X
  1122. X#ifdef S_IFBLK
  1123. X    case LF_BLK:
  1124. X        hstat.st_mode |= S_IFBLK;
  1125. X        goto make_node;
  1126. X#endif
  1127. X
  1128. X#ifdef S_IFIFO
  1129. X    /* If local system doesn't support FIFOs, use default case */
  1130. X    case LF_FIFO:
  1131. X        hstat.st_mode |= S_IFIFO;
  1132. X        hstat.st_rdev = 0;        /* FIXME, do we need this? */
  1133. X        goto make_node;
  1134. X#endif
  1135. X
  1136. X    make_node:
  1137. X        check = mknod(skipcrud+head->header.name,
  1138. X                  (int) hstat.st_mode, (int) hstat.st_rdev);
  1139. X        if (check != 0) {
  1140. X            if (make_dirs(skipcrud+head->header.name))
  1141. X                goto make_node;
  1142. X            annofile(stderr, tar);
  1143. X            fprintf(stderr, "Could not make ");
  1144. X            perror(skipcrud+head->header.name);
  1145. X            break;
  1146. X        };
  1147. X        goto set_filestat;
  1148. X
  1149. X    case LF_DIR:
  1150. X        namelen = strlen(skipcrud+head->header.name)-1;
  1151. X    really_dir:
  1152. X        /* Check for trailing /, and zap as many as we find. */
  1153. X        while (namelen && head->header.name[skipcrud+namelen] == '/')
  1154. X            head->header.name[skipcrud+namelen--] = '\0';
  1155. X        
  1156. X    again_dir:
  1157. X#ifdef AMIGA
  1158. X        /* don't mkdir("", mode) */
  1159. X        check = 0;
  1160. X        if (*(skipcrud+head->header.name))
  1161. X#endif
  1162. X        check = mkdir(skipcrud+head->header.name,
  1163. X                  0300 | (int)hstat.st_mode);
  1164. X        if (check != 0) {
  1165. X            if (make_dirs(skipcrud+head->header.name))
  1166. X                goto again_dir;
  1167. X            /* If we're trying to create '.', let it be. */
  1168. X            if (head->header.name[skipcrud+namelen] == '.' && 
  1169. X                (namelen==0 ||
  1170. X                 head->header.name[skipcrud+namelen-1]=='/'))
  1171. X                goto check_perms;
  1172. X            annofile(stderr, tar);
  1173. X            fprintf(stderr, "Could not make directory ");
  1174. X            perror(skipcrud+head->header.name);
  1175. X            break;
  1176. X        }
  1177. X        
  1178. X    check_perms:
  1179. X        if (0300 != (0300 & (int) hstat.st_mode)) {
  1180. X            hstat.st_mode |= 0300;
  1181. X            annofile(stderr, tar);
  1182. X            fprintf(stderr,
  1183. X              "Added write & execute permission to directory %s\n",
  1184. X              skipcrud+head->header.name);
  1185. X        }
  1186. X
  1187. X        goto set_filestat;
  1188. X        /* FIXME, Remember timestamps for after files created? */
  1189. X        /* FIXME, change mode after files created (if was R/O dir) */
  1190. X
  1191. X    }
  1192. X
  1193. X    /* We don't need to save it any longer. */
  1194. X    saverec((union record **) 0);    /* Unsave it */
  1195. X}
  1196. X
  1197. X/*
  1198. X * After a file/link/symlink/dir creation has failed, see if
  1199. X * it's because some required directory was not present, and if
  1200. X * so, create all required dirs.
  1201. X */
  1202. Xint
  1203. Xmake_dirs(pathname)
  1204. X    char *pathname;
  1205. X{
  1206. X    char *p;            /* Points into path */
  1207. X    int madeone = 0;        /* Did we do anything yet? */
  1208. X    int save_errno = errno;        /* Remember caller's errno */
  1209. X    int check;
  1210. X
  1211. X    if (errno != ENOENT)
  1212. X        return 0;        /* Not our problem */
  1213. X#if defined(AMIGA) && defined(LATTICE)
  1214. X    /*
  1215. X     * ARRRRGGGGHHHH!  If delete bit is not set, open fails with ENOENT.
  1216. X     * I think it should be EPERM.  So we check for the file's existance
  1217. X     * here and return if it does exist.
  1218. X     */
  1219. X    if (!access(pathname, O_RDONLY))
  1220. X    {
  1221. X        errno = EPERM;        /* perror should say "Permission Denied"
  1222. X                     * but, says something stupid instead */
  1223. X        return(0);            /* Not our problem */
  1224. X    }
  1225. X#endif
  1226. X    for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
  1227. X        /* Avoid mkdir of empty string, if leading or double '/' */
  1228. X        if (p == pathname || p[-1] == '/')
  1229. X            continue;
  1230. X        /* Avoid mkdir where last part of path is '.' */
  1231. X        if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  1232. X            continue;
  1233. X        *p = 0;                /* Truncate the path there */
  1234. X        check = mkdir (pathname, 0777);    /* Try to create it as a dir */
  1235. X        if (check == 0) {
  1236. X            /* Fix ownership */
  1237. X            if (we_are_root) {
  1238. X                if (chown(pathname, hstat.st_uid,
  1239. X                      hstat.st_gid) < 0) {
  1240. X                    annofile(stderr, tar);
  1241. X                    perror(pathname);
  1242. X                }
  1243. X            }
  1244. X            pr_mkdir(pathname, p-pathname, notumask&0777, stdout);
  1245. X            madeone++;        /* Remember if we made one */
  1246. X            *p = '/';
  1247. X            continue;
  1248. X        }
  1249. X        *p = '/';
  1250. X        if (errno == EEXIST)        /* Directory already exists */
  1251. X            continue;
  1252. X        /*
  1253. X         * Some other error in the mkdir.  We return to the caller.
  1254. X         */
  1255. X        break;
  1256. X    }
  1257. X
  1258. X    errno = save_errno;        /* Restore caller's errno */
  1259. X    return madeone;            /* Tell them to retry if we made one */
  1260. X}
  1261. END_OF_FILE
  1262. if test 13710 -ne `wc -c <'extract.c'`; then
  1263.     echo shar: \"'extract.c'\" unpacked with wrong size!
  1264. fi
  1265. # end of 'extract.c'
  1266. fi
  1267. if test -f 'port.c' -a "${1}" != "-c" ; then 
  1268.   echo shar: Will not clobber existing file \"'port.c'\"
  1269. else
  1270. echo shar: Extracting \"'port.c'\" \(12968 characters\)
  1271. sed "s/^X//" >'port.c' <<'END_OF_FILE'
  1272. X/*
  1273. X * @(#)port.c 1.15    87/11/05    Public Domain, by John Gilmore, 1986
  1274. X *
  1275. X * These are routines not available in all environments.
  1276. X *
  1277. X * I know this introduces an extra level of subroutine calls and is
  1278. X * slightly slower.  Frankly, my dear, I don't give a damn.  Let the
  1279. X * Missed-Em Vee losers suffer a little.  This software is proud to
  1280. X * have been written on a BSD system.
  1281. X */
  1282. X#ifdef AMIGA
  1283. X#include <stdlib.h>
  1284. X#endif
  1285. X
  1286. X#include <stdio.h>
  1287. X#include <sys/types.h>
  1288. X#include <sys/stat.h>
  1289. X#include <signal.h>
  1290. X#include <errno.h>
  1291. X
  1292. X#if defined(MSDOS) || defined(AMIGA)
  1293. X#include <fcntl.h>
  1294. X#else
  1295. X#include <sys/file.h>
  1296. X#endif
  1297. X
  1298. X#include "tar.h"
  1299. X
  1300. Xextern char **environ;
  1301. X
  1302. X#ifndef NULL
  1303. X#define NULL 0
  1304. X#endif
  1305. X
  1306. X/*
  1307. X * Some people (e.g. V7) don't have a #define for these.
  1308. X */
  1309. X#ifndef    O_BINARY
  1310. X#define    O_BINARY    0
  1311. X#endif
  1312. X#ifndef    O_RDONLY
  1313. X#define    O_RDONLY    0
  1314. X#endif
  1315. X
  1316. X
  1317. X#include "port.h"
  1318. X
  1319. X
  1320. X/*
  1321. X * Some computers are not so crass as to align themselves into the BSD
  1322. X * or USG camps.  If a system supplies all of the routines we fake here,
  1323. X * add it to the list in the #ifndefs below and it'll all be skipped.
  1324. X * Make sure to add a matching #endif at the end of the file!
  1325. X *
  1326. X * We are avoiding #if defined() here for the sake of Minix, which comes
  1327. X * with the severely broken Amsterdam Compiler Kit.  Thanks, Andy!
  1328. X */
  1329. X#ifndef mc300
  1330. X#ifndef mc500
  1331. X#ifndef mc700
  1332. X
  1333. X
  1334. X#ifndef BSD42
  1335. X/*
  1336. X * lstat() is a stat() which does not follow symbolic links.
  1337. X * If there are no symbolic links, just use stat().
  1338. X */
  1339. Xint
  1340. Xlstat (path, buf)
  1341. X    char *path;
  1342. X    struct stat *buf;
  1343. X{
  1344. X    extern int stat ();
  1345. X    return (stat (path, buf));
  1346. X}
  1347. X
  1348. X/*
  1349. X * valloc() does a malloc() on a page boundary.  On some systems,
  1350. X * this can make large block I/O more efficient.
  1351. X */
  1352. Xchar *
  1353. Xvalloc (size)
  1354. X    unsigned size;
  1355. X{
  1356. X#ifndef AMIGA
  1357. X    extern char *malloc ();
  1358. X#endif
  1359. X    return (malloc (size));
  1360. X}
  1361. X
  1362. X/*
  1363. X *                NMKDIR.C
  1364. X *
  1365. X * Written by Robert Rother, Mariah Corporation, August 1985. 
  1366. X *
  1367. X * I wrote this out of shear disgust with myself because I couldn't
  1368. X * figure out how to do this in /bin/sh.
  1369. X *
  1370. X * If you want it, it's yours.  All I ask in return is that if you
  1371. X * figure out how to do this in a Bourne Shell script you send me
  1372. X * a copy.
  1373. X *                    sdcsvax!rmr or rmr@uscd
  1374. X*
  1375. X* Severely hacked over by John Gilmore to make a 4.2BSD compatible
  1376. X* subroutine.    11Mar86; hoptoad!gnu
  1377. X*
  1378. X* Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
  1379. X* subroutine didn't return EEXIST.  It does now.
  1380. X*/
  1381. X
  1382. X/*
  1383. X * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  1384. X */
  1385. X#if !defined(MSDOS) && !defined(AMIGA)
  1386. Xint
  1387. Xmkdir(dpath, dmode)
  1388. X    char *dpath;
  1389. X    int dmode;
  1390. X{
  1391. X    int cpid, status;
  1392. X    struct stat statbuf;
  1393. X    extern int errno;
  1394. X
  1395. X    if (stat(dpath,&statbuf) == 0) {
  1396. X        errno = EEXIST;        /* Stat worked, so it already exists */
  1397. X        return -1;
  1398. X    }
  1399. X
  1400. X    /* If stat fails for a reason other than non-existence, return error */
  1401. X    if (errno != ENOENT) return -1; 
  1402. X
  1403. X    switch (cpid = fork()) {
  1404. X
  1405. X    case -1:            /* Error in fork() */
  1406. X        return(-1);        /* Errno is set already */
  1407. X
  1408. X    case 0:                /* Child process */
  1409. X        /*
  1410. X         * Cheap hack to set mode of new directory.  Since this
  1411. X         * child process is going away anyway, we zap its umask.
  1412. X         * FIXME, this won't suffice to set SUID, SGID, etc. on this
  1413. X         * directory.  Does anybody care?
  1414. X         */
  1415. X        status = umask(0);    /* Get current umask */
  1416. X        status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  1417. X        execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  1418. X        _exit(-1);        /* Can't exec /bin/mkdir */
  1419. X    
  1420. X    default:            /* Parent process */
  1421. X        while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  1422. X    }
  1423. X
  1424. X    if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  1425. X        errno = EIO;        /* We don't know why, but */
  1426. X        return -1;        /* /bin/mkdir failed */
  1427. X    }
  1428. X
  1429. X    return 0;
  1430. X}
  1431. X#endif    /* MSDOS */
  1432. X#endif
  1433. X
  1434. X/* This next bit is called "doing OR on Minix cpp", e.g. without defined(). */
  1435. X#undef WANTSTRING
  1436. X#ifdef USG
  1437. X#define WANTSTRING
  1438. X#endif
  1439. X#ifdef MSDOS
  1440. X#define WANTSTRING
  1441. X#endif
  1442. X#ifdef AMIGA
  1443. X#define WANTSTRING
  1444. X#endif
  1445. X
  1446. X#ifdef WANTSTRING
  1447. X/*
  1448. X * Translate V7 style into Sys V style.
  1449. X */
  1450. X#include <string.h>
  1451. X#ifndef AMIGA
  1452. X#include <memory.h>
  1453. X#endif
  1454. X
  1455. Xchar *
  1456. Xindex (s, c)
  1457. X    char *s;
  1458. X    int c;
  1459. X{
  1460. X    return (strchr (s, c));
  1461. X}
  1462. X
  1463. Xvoid
  1464. Xbcopy (s1, s2, n)
  1465. X    char *s1, *s2;
  1466. X    int n;
  1467. X{
  1468. X    (void) memcpy (s2, s1, n);
  1469. X}
  1470. X
  1471. Xvoid
  1472. Xbzero (s1, n)
  1473. X    char *s1;
  1474. X    int n;
  1475. X{
  1476. X    (void) memset(s1, 0, n);
  1477. X}
  1478. X
  1479. Xint
  1480. Xbcmp(s1, s2, n)
  1481. X    char    *s1, *s2;
  1482. X    int    n;
  1483. X{
  1484. X    return memcmp(s1, s2, n);
  1485. X}
  1486. X#endif
  1487. X
  1488. X#ifdef MINIX
  1489. X/* Minix has bcopy but not bzero, and no memset.  Thanks, Andy. */
  1490. Xvoid
  1491. Xbzero (s1, n)
  1492. X    register char *s1;
  1493. X    register int n;
  1494. X{
  1495. X    while (n--) *s1++ = '\0';
  1496. X}
  1497. X
  1498. X/* It also has no bcmp() */
  1499. Xint
  1500. Xbcmp (s1, s2, n) 
  1501. X    register char *s1,*s2;
  1502. X    register int n;
  1503. X{
  1504. X    for ( ; n-- ; ++s1, ++s2) {
  1505. X        if (*s1 != *s2) return *s1 - *s2;
  1506. X    }
  1507. X    return 0;
  1508. X}
  1509. X
  1510. X/*
  1511. X * Groan, Minix doesn't have execlp either!
  1512. X *
  1513. X * execlp(file,arg0,arg1...argn,(char *)NULL)
  1514. X * exec a program, automatically searching for the program through
  1515. X * all the directories on the PATH.
  1516. X *
  1517. X * This version is naive about variable argument lists, it assumes
  1518. X * a straightforward C calling sequence.  If your system has odd stacks
  1519. X * *and* doesn't have execlp, YOU get to fix it.
  1520. X */
  1521. Xint
  1522. Xexeclp(filename, arg0)
  1523. X    char *filename, *arg0;
  1524. X{
  1525. X    extern char *malloc(), *getenv(), *index();
  1526. X    extern int errno;
  1527. X    register char *p, *path;    
  1528. X    char **argstart = &arg0;
  1529. X    register char *fnbuffer;
  1530. X    struct stat statbuf;
  1531. X
  1532. X    if ((p = getenv("PATH")) == NULL) {
  1533. X        /* couldn't find path variable -- try to exec given filename */
  1534. X        return execve(filename, argstart, environ);
  1535. X    }
  1536. X
  1537. X    /*
  1538. X     * make a place to build the filename.  We malloc larger than we
  1539. X     * need, but we know it will fit in this.
  1540. X     */
  1541. X    fnbuffer = malloc( strlen(p) + 1 + strlen(filename) );
  1542. X    if (fnbuffer == NULL) {
  1543. X        errno = ENOMEM;
  1544. X        return -1;
  1545. X    }
  1546. X
  1547. X    /*
  1548. X     * try each component of the path to see if the file's there
  1549. X     * and executable.
  1550. X     */
  1551. X    for (path = p ; path ; path = p) {
  1552. X        /* construct full path name to try */
  1553. X        if ((p = index(path,':')) == NULL) {
  1554. X            strcpy(fnbuffer, path);
  1555. X        } else {
  1556. X            strncpy(fnbuffer, path, p-path);
  1557. X            fnbuffer[p-path] = '\0';
  1558. X            p++;        /* Skip : for next time */
  1559. X        }
  1560. X        if (strlen(fnbuffer) != 0)
  1561. X            strcat(fnbuffer,"/");
  1562. X        strcat(fnbuffer,filename);
  1563. X
  1564. X        /* check to see if file is there and is a normal file */
  1565. X        if (stat(fnbuffer, &statbuf) < 0) {
  1566. X            if (errno == ENOENT)
  1567. X                continue; /* file not there,keep on looking */
  1568. X            else
  1569. X                goto fail; /* failed for some reason, return */
  1570. X        }
  1571. X        if ( (statbuf.st_mode & S_IFMT) != S_IFREG) continue;
  1572. X
  1573. X        if (execve(fnbuffer, argstart, environ) < 0
  1574. X            && errno != ENOENT
  1575. X            && errno != ENOEXEC) {
  1576. X            /* failed, for some other reason besides "file
  1577. X             * not found" or "not a.out format"
  1578. X             */
  1579. X            goto fail;
  1580. X        }
  1581. X
  1582. X        /*
  1583. X         * If we got error ENOEXEC, the file is executable but is
  1584. X         * not an object file.  Try to execute it as a shell script,
  1585. X         * returning error if we can't execute /bin/sh.
  1586. X         *
  1587. X         * FIXME, this code is broken in several ways.  Shell
  1588. X         * scripts should not in general be executed by the user's
  1589. X         * SHELL variable program.  On more mature systems, the
  1590. X         * script can specify with #!/bin/whatever.  Also, this
  1591. X         * code clobbers argstart[-1] if the exec of the shell
  1592. X         * fails.
  1593. X         */
  1594. X        if (errno == ENOEXEC) {
  1595. X            char *shell;
  1596. X
  1597. X            /* Try to execute command "sh arg0 arg1 ..." */
  1598. X            if ((shell = getenv("SHELL")) == NULL)
  1599. X                shell = "/bin/sh";
  1600. X            argstart[-1] = shell;
  1601. X            argstart[0] = fnbuffer;
  1602. X            execve(shell, &argstart[-1], environ);
  1603. X            goto fail;    /* Exec didn't work */
  1604. X        }
  1605. X
  1606. X        /* 
  1607. X         * If we succeeded, the execve() doesn't return, so we
  1608. X         * can only be here is if the file hasn't been found yet.
  1609. X         * Try the next place on the path.
  1610. X         */
  1611. X    }
  1612. X
  1613. X    /* all attempts failed to locate the file.  Give up. */
  1614. X    errno = ENOENT;
  1615. X
  1616. Xfail:
  1617. X    free(fnbuffer);
  1618. X    return -1;
  1619. X}
  1620. X#endif /* MINIX */
  1621. X
  1622. X
  1623. X#ifdef EMUL_OPEN3
  1624. X#include "open3.h"
  1625. X/*
  1626. X * open3 -- routine to emulate the 3-argument open system
  1627. X * call that is present in most modern Unix systems.
  1628. X * This version attempts to support all the flag bits except for O_NDELAY
  1629. X * and O_APPEND, which are silently ignored.  The emulation is not as efficient
  1630. X * as the real thing (at worst, 4 system calls instead of one), but there's
  1631. X * not much I can do about that.
  1632. X *
  1633. X * Written 6/10/87 by rmtodd@uokmax
  1634. X *
  1635. X * open3(path, flag, mode)
  1636. X * Attempts to open the file specified by
  1637. X * the given pathname.  The following flag bits (#defined in tar.h)
  1638. X * specify options to the routine:
  1639. X *    O_RDONLY    file open for read only
  1640. X *    O_WRONLY    file open for write only
  1641. X *    O_RDWR        file open for both read & write
  1642. X * (Needless to say, you should only specify one of the above).
  1643. X *     O_CREAT        file is created with specified mode if it needs to be.
  1644. X *    O_TRUNC        if file exists, it is truncated to 0 bytes
  1645. X *    O_EXCL        used with O_CREAT--routine returns error if file exists
  1646. X * Function returns file descriptor if successful, -1 and errno if not.
  1647. X */
  1648. X
  1649. X/*
  1650. X * array to give arguments to access for various modes
  1651. X * FIXME, this table depends on the specific integer values of O_XXX,
  1652. X * and also contains integers (args to 'access') that should be #define's.
  1653. X */
  1654. Xstatic int modes[] =
  1655. X    {
  1656. X        04, /* O_RDONLY */
  1657. X        02, /* O_WRONLY */
  1658. X        06, /* O_RDWR */
  1659. X        06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
  1660. X    };
  1661. X
  1662. X/* Shut off the automatic emulation of open(), we'll need it. */
  1663. X#undef open
  1664. X
  1665. Xint
  1666. Xopen3(path, flags, mode)
  1667. Xchar *path;
  1668. Xint flags, mode;
  1669. X{
  1670. X    extern int errno;
  1671. X    int exists = 1;
  1672. X    int call_creat = 0;
  1673. X    int fd;
  1674. X    /*
  1675. X     * We actually do the work by calling the open() or creat() system
  1676. X     * call, depending on the flags.  Call_creat is true if we will use 
  1677. X     * creat(), false if we will use open().
  1678. X     */
  1679. X
  1680. X    /*
  1681. X     * See if the file exists and is accessible in the requested mode. 
  1682. X     *
  1683. X     * Strictly speaking we shouldn't be using access, since access checks
  1684. X     * against real uid, and the open call should check against euid.
  1685. X     * Most cases real uid == euid, so it won't matter.   FIXME.
  1686. X     * FIXME, the construction "flags & 3" and the modes table depends
  1687. X     * on the specific integer values of the O_XXX #define's.  Foo!
  1688. X     */
  1689. X    if (access(path,modes[flags & 3]) < 0) {
  1690. X        if (errno == ENOENT) {
  1691. X            /* the file does not exist */
  1692. X            exists = 0;
  1693. X        } else {
  1694. X            /* probably permission violation */
  1695. X            if (flags & O_EXCL) {
  1696. X                /* Oops, the file exists, we didn't want it. */
  1697. X                /* No matter what the error, claim EEXIST. */
  1698. X                errno = EEXIST;
  1699. X            }
  1700. X            return -1;
  1701. X        }
  1702. X    }
  1703. X
  1704. X    /* if we have the O_CREAT bit set, check for O_EXCL */
  1705. X    if (flags & O_CREAT) {
  1706. X        if ((flags & O_EXCL) && exists) {
  1707. X            /* Oops, the file exists and we didn't want it to. */
  1708. X            errno = EEXIST;
  1709. X            return -1;
  1710. X        }
  1711. X        /*
  1712. X         * If the file doesn't exist, be sure to call creat() so that
  1713. X         * it will be created with the proper mode.
  1714. X         */
  1715. X        if (!exists) call_creat = 1;
  1716. X    } else {
  1717. X        /* If O_CREAT isn't set and the file doesn't exist, error. */
  1718. X        if (!exists) {
  1719. X            errno = ENOENT;
  1720. X            return -1;
  1721. X        }
  1722. X    }
  1723. X
  1724. X    /*
  1725. X     * If the O_TRUNC flag is set and the file exists, we want to call
  1726. X     * creat() anyway, since creat() guarantees that the file will be
  1727. X     * truncated and open()-for-writing doesn't.
  1728. X     * (If the file doesn't exist, we're calling creat() anyway and the
  1729. X     * file will be created with zero length.)
  1730. X     */
  1731. X    if ((flags & O_TRUNC) && exists) call_creat = 1;
  1732. X    /* actually do the call */
  1733. X    if (call_creat) {
  1734. X        /*
  1735. X         * call creat.  May have to close and reopen the file if we
  1736. X         * want O_RDONLY or O_RDWR access -- creat() only gives
  1737. X         * O_WRONLY.
  1738. X         */
  1739. X        fd = creat(path,mode);
  1740. X        if (fd < 0 || (flags & O_WRONLY)) return fd;
  1741. X        if (close(fd) < 0) return -1;
  1742. X        /* Fall out to reopen the file we've created */
  1743. X    }
  1744. X
  1745. X    /*
  1746. X     * calling old open, we strip most of the new flags just in case.
  1747. X     */
  1748. X    return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY));
  1749. X}
  1750. X#endif
  1751. X
  1752. X#endif /* MASSCOMP mc700 */
  1753. X#endif /* MASSCOMP mc500 */
  1754. X#endif /* MASSCOMP mc300 */
  1755. X
  1756. X
  1757. X
  1758. X#if defined(MSDOS) || defined(AMIGA)
  1759. X/* Fake mknod by complaining */
  1760. Xint
  1761. Xmknod(path, mode, dev)
  1762. X    char        *path;
  1763. X    unsigned short    mode;
  1764. X    dev_t        dev;
  1765. X{
  1766. X    extern int    errno;
  1767. X    int        fd;
  1768. X    
  1769. X    errno = ENXIO;        /* No such device or address */
  1770. X    return -1;        /* Just give an error */
  1771. X}
  1772. X
  1773. X/* Fake links by copying */
  1774. Xint
  1775. Xlink(path1, path2)
  1776. X    char        *path1;
  1777. X    char        *path2;
  1778. X{
  1779. X    char    buf[256];
  1780. X    int    ifd, ofd;
  1781. X    int    nrbytes;
  1782. X    int    nwbytes;
  1783. X
  1784. X    fprintf(stderr, "%s: %s: cannot link to %s, copying instead\n",
  1785. X        tar, path1, path2);
  1786. X    if ((ifd = open(path1, O_RDONLY|O_BINARY)) < 0)
  1787. X        return -1;
  1788. X    if ((ofd = creat(path2, 0666)) < 0)
  1789. X        return -1;
  1790. X#ifdef MSDOS
  1791. X    setmode(ofd, O_BINARY);
  1792. X#endif
  1793. X    while ((nrbytes = read(ifd, buf, sizeof(buf))) > 0) {
  1794. X        if ((nwbytes = write(ofd, buf, nrbytes)) != nrbytes) {
  1795. X            nrbytes = -1;
  1796. X            break;
  1797. X        }
  1798. X    }
  1799. X    /* Note use of "|" rather than "||" below: we want to close
  1800. X     * the files even if an error occurs.
  1801. X     */
  1802. X    if ((nrbytes < 0) | (0 != close(ifd)) | (0 != close(ofd))) {
  1803. X        unlink(path2);
  1804. X        return -1;
  1805. X    }
  1806. X    return 0;
  1807. X}
  1808. X
  1809. X/* everyone owns everything on MS-DOS (or is it no one owns anything?) */
  1810. Xint
  1811. Xchown(path, uid, gid)
  1812. X    char    *path;
  1813. X    int    uid;
  1814. X    int    gid;
  1815. X{
  1816. X    return 0;
  1817. X}
  1818. X
  1819. Xint
  1820. Xgeteuid()
  1821. X{
  1822. X    return 0;
  1823. X}
  1824. X#endif    /* MSDOS */
  1825. END_OF_FILE
  1826. if test 12968 -ne `wc -c <'port.c'`; then
  1827.     echo shar: \"'port.c'\" unpacked with wrong size!
  1828. fi
  1829. # end of 'port.c'
  1830. fi
  1831. echo shar: End of archive 3 \(of 5\).
  1832. cp /dev/null ark3isdone
  1833. MISSING=""
  1834. for I in 1 2 3 4 5 ; do
  1835.     if test ! -f ark${I}isdone ; then
  1836.     MISSING="${MISSING} ${I}"
  1837.     fi
  1838. done
  1839. if test "${MISSING}" = "" ; then
  1840.     echo You have unpacked all 5 archives.
  1841.     rm -f ark[1-9]isdone
  1842. else
  1843.     echo You still need to unpack the following archives:
  1844.     echo "        " ${MISSING}
  1845. fi
  1846. ##  End of shell archive.
  1847. exit 0
  1848. -- 
  1849. Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
  1850. Mail comments to the moderator at <amiga-request@cs.odu.edu>.
  1851. Post requests for sources, and general discussion to comp.sys.amiga.
  1852.